package org.openfdtd;

import com.sun.j3d.utils.universe.SimpleUniverse;
import java.awt.Color;
import java.awt.GraphicsConfiguration;
import java.util.ArrayList;
import java.util.Arrays;
import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.Geometry;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.View;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.vecmath.Color3f;
import javax.vecmath.Vector3f;
import org.openfdtd.core3d.ViewGrid;
import org.openfdtd.core3d.EditableObject3D;
import org.openfdtd.core3d.EditableUniverse;
import org.openfdtd.core3d.SceneComponent;
import org.openfdtd.core3d.Surface;
import org.openfdtd.gui.MainFrame;

/**
 *
 * @author Dorian C. Langbeck
 */
public class Runner implements Runnable {
    private EditableUniverse universe;

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runner());
    }

    public void run() {
        preConfigure();
        configureVisual();

        try {
            loadApplication();
        } catch (Exception ex) {
            ex.printStackTrace();
            System.exit(1);
        }

        //FIX: Executa o GC periodicamente a cada 30 segundos.
        //TODO: Implementar um metodo mais eficiente para liberar a memória.
        new Thread(new Runnable() {
            public void run() {
                try {
                    while(true) {
                        Thread.sleep(30000);
                        System.gc();
                    }
                } catch (InterruptedException ex) {
                    JOptionPane.showMessageDialog(null, "Falha no assistente de liberacao de memoria.\nSem ele o programa pode continuar a funcionar, porem o consumo de memoria aumentara consideravelmente durante o tempo de execução.", "", JOptionPane.ERROR_MESSAGE);
                }
            }
        }).start();
    }

    private void loadApplication() {
        GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
        Canvas3D canvas = new Canvas3D(config);

        universe = new EditableUniverse(canvas, new Color3f(Color.WHITE));
        universe.getViewingPlatform().setNominalViewingTransform();
        universe.add(new ViewGrid(5, 100));

        QuadArray qa = new QuadArray(4, GeometryArray.COORDINATES | GeometryArray.NORMALS);
        qa.setCoordinates(0, new double[] {
            .0, .0, .0,
            .0, .5, .0,
            .5, .5, .0,
            .5, .0, .0
        });

        Surface[] faces = new Surface[] {
            new Surface(new double[] {
                0.5, 0.5, 0.5,
                0.5, 1.0, 0.5,
                1.0, 1.0, 0.5,
                1.0, 0.5, 0.5
            }),

            new Surface(new double[] {
                1.0, 0.5, 1.0,
                1.0, 1.0, 1.0,
                0.5, 1.0, 1.0,
                0.5, 0.5, 1.0
            }),

            new Surface(new double[] {
                0.5, 0.5, 0.5,
                0.5, 0.5, 1.0,
                0.5, 1.0, 1.0,
                0.5, 1.0, 0.5
            }),

            new Surface(new double[] {
                1.0, 1.0, 0.5,
                1.0, 1.0, 1.0,
                1.0, 0.5, 1.0,
                1.0, 0.5, 0.5
            }),

            new Surface(new double[] {
                0.5, 1.0, 0.5,
                0.5, 1.0, 1.0,
                1.0, 1.0, 1.0,
                1.0, 1.0, 0.5
            }),

            new Surface(new double[] {
                1.0, 0.5, 0.5,
                1.0, 0.5, 1.0,
                0.5, 0.5, 1.0,
                0.5, 0.5, 0.5
            })
        };

        Surface[] faces2 = new Surface[] {
            new Surface(new double[] {
                1.5, 1.5, 1.5,
                1.5, 2.0, 1.5,
                2.0, 2.0, 1.5,
                2.0, 1.5, 1.5
            }),

            new Surface(new double[] {
                2.0, 1.5, 2.0,
                2.0, 2.0, 2.0,
                1.5, 2.0, 2.0,
                1.5, 1.5, 2.0
            }),

            new Surface(new double[] {
                1.5, 1.5, 1.5,
                1.5, 1.5, 2.0,
                1.5, 2.0, 2.0,
                1.5, 2.0, 1.5
            }),

            new Surface(new double[] {
                2.0, 2.0, 1.5,
                2.0, 2.0, 2.0,
                2.0, 1.5, 2.0,
                2.0, 1.5, 1.5
            }),

            new Surface(new double[] {
                1.5, 2.0, 1.5,
                1.5, 2.0, 2.0,
                2.0, 2.0, 2.0,
                2.0, 2.0, 1.5
            }),

            new Surface(new double[] {
                2.0, 1.5, 1.5,
                2.0, 1.5, 2.0,
                1.5, 1.5, 2.0,
                1.5, 1.5, 1.5
            })
        };

        EditableObject3D obj2 = new EditableObject3D(faces2);
        universe.add(obj2);

        EditableObject3D obj = new EditableObject3D(faces);
        universe.add(obj);

        new MainFrame(universe).setVisible(true);
    }

    private void preConfigure() {
        //FIX: Correcao para mostrar menus corretamente sobre o canvas
        JPopupMenu.setDefaultLightWeightPopupEnabled(false);
        ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false);
    }

    private void configureVisual() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ex) { }
    }
}
